﻿using Apollo.AST;
using Apollo.LexerUtils;
using Apollo.TokenUtils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Apollo.ParserUtils
{
    /// <summary>
    /// 语法分析器
    /// </summary>
    internal class Parser
    {
        /// <summary>
        /// 优先级枚举定义
        /// </summary>
        public static Dictionary<TokenType, Precedence> m_precedences = new()
        {
            [TokenType.PLUS] =        Precedence.SUM,
            [TokenType.MINUS] =       Precedence.SUM,
            [TokenType.ASTERISK] =    Precedence.PRODUCT,
            [TokenType.SLASH] =       Precedence.PRODUCT,
        };

        // 前缀表达式构建函数原型定义
        public delegate Expression Prefix_Parse_Fn();

        // 中缀表达式函数原型定义
        public delegate Expression Infix_Parse_Fn(Expression expr);

        // 后缀表达式函数原型定义
        public delegate Expression Postfix_Parse_Fn(Expression expr);


        /// <summary>
        /// 前缀表达式列表
        /// </summary>
        public Dictionary<TokenType, Prefix_Parse_Fn> m_prefix_parse_fns;

        /// <summary>
        /// 中缀表达式列表
        /// </summary>
        public Dictionary<TokenType, Infix_Parse_Fn> m_infix_parse_fns;

        /// <summary>
        /// 后缀表达式列表
        /// </summary>
        public Dictionary<TokenType, Postfix_Parse_Fn> m_postfix_parse_fns;

        /// <summary>
        /// 整数实用类
        /// </summary>
        /// <returns></returns>
        private Expression Parse_Integer()
        {
            ExpressionInt e = new();
            e.NodeToken = m_curr;
            e.Val = int.Parse(m_curr.Literal);
            return e;
        }

        /// <summary>
        /// 遇到左括号，调用
        /// </summary>
        /// <returns></returns>
        private Expression Parse_Group()
        {
            Next_Token();
            var e = Parse_Expression(Precedence.LOWEST);
            if (!Expect_Peek_Token(TokenType.RPAREN))     // 未找到右括号， 调用结束
            {
                return null;
            }
            return e;
        }

        /// <summary>
        /// 遇到运算符，调用中缀表达式
        /// </summary>
        /// <param name="expr"></param>
        /// <returns></returns>
        private Expression Parse_Infix(Expression expr)
        {
            var e = new Infix();
            e.NodeToken = m_curr;
            e.m_operator = m_curr.Literal;
            e.m_left = expr;
            Precedence precedence = Curr_Token_Precedence();
            Next_Token();
            e.m_right = Parse_Expression(precedence);
            return e;
        }

        /// <summary>
        /// 遇到++,--运算符，调用后缀表达式
        /// </summary>
        /// <param name="expr"></param>
        /// <returns></returns>
        private Expression Parse_Postfix(Expression expr)
        {
            var e = new Infix();
            e.NodeToken = m_curr;
            e.m_operator = m_curr.Literal;
            e.m_left = expr;
            Precedence precedence = Curr_Token_Precedence();
            Next_Token();
            e.m_right = Parse_Expression(precedence);
            return e;
        }

        #region  私有变量定义
        private Lexer m_lexer;
        private Token m_curr;
        private Token m_peek;
        public List<string> m_errors = new();
        #endregion

        /// <summary>
        /// 程序段的实现
        /// </summary>
        /// <returns></returns>
        public AST.Program  Parse_Program()
        {
            var section = new AST.Program();
            while (m_curr.Type != TokenType.EOF)
            {
                var stmt = Parse_Statement();
                if (stmt != null)
                {
                    section.m_statements.Add(stmt);
                }
                Next_Token();
            }
            return section;
        }

        /// <summary>
        /// 语句的实现
        /// </summary>
        /// <returns></returns>
        public Statement Parse_Statement()
        {
            return Parse_Expression_Statement();
        }

        /// <summary>
        /// 表达式的实现
        /// </summary>
        /// <returns></returns>
        public ExpressionStatement  Parse_Expression_Statement()
        {
            ExpressionStatement s = new();
            s.NodeToken = m_curr;
            s.m_expression = Parse_Expression(Precedence.LOWEST);
            while (Peek_Token_Is(TokenType.SEMICOLON))
            {
                Next_Token();
            }
            return s;
        }

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public Parser()
        {
            
        }

        /// <summary>
        /// 在词法分析器的基础上构建语法分析器
        /// </summary>
        /// <param name="lexer"></param>
        public Parser(Lexer lexer)
        {
            m_lexer = lexer;
            Next_Token();
            Next_Token();

            // 构建前缀表达式对应的处理函数
            m_prefix_parse_fns = new();
            m_prefix_parse_fns.TryAdd(TokenType.INTEGER, Parse_Integer);
            m_prefix_parse_fns.TryAdd(TokenType.LPAREN, Parse_Group);

            // 构建中缀表达式对应的处理函数列表
            m_infix_parse_fns = new();
            m_infix_parse_fns.TryAdd(TokenType.PLUS, Parse_Infix);
            m_infix_parse_fns.TryAdd(TokenType.MINUS, Parse_Infix);
            m_infix_parse_fns.TryAdd(TokenType.ASTERISK, Parse_Infix);
            m_infix_parse_fns.TryAdd(TokenType.SLASH, Parse_Infix);

            // 构建后缀表达式对应的处理函数列表
            m_postfix_parse_fns = new();
            m_postfix_parse_fns.TryAdd(TokenType.PLUS_PLUS, Parse_Postfix);
            m_postfix_parse_fns.TryAdd(TokenType.MINUS_MINUS, Parse_Postfix);
        }

        /// <summary>
        /// 查找下一个词
        /// </summary>
        public void Next_Token()
        {
            m_curr = m_peek;
            m_peek = m_lexer.Next_Token();
        }

        /// <summary>
        /// 判断当前Token是否为该符号
        /// </summary>
        /// <param name="tokenType"></param>
        /// <returns></returns>
        public bool Curr_Token_Is(TokenType tokenType)
        {
            return m_curr.Equals(tokenType);
        }

        /// <summary>
        /// 判断下一个Token是否为该符号
        /// </summary>
        /// <param name="tokenType"></param>
        /// <returns></returns>
        public bool Peek_Token_Is(TokenType tokenType)
        {
            return m_peek.Equals(tokenType);
        }

        /// <summary>
        /// 如果下一个符号是预计的符号
        /// </summary>
        /// <param name="tokenType"></param>
        /// <returns></returns>
        public bool Expect_Peek_Token(TokenType tokenType)
        {
            if (Peek_Token_Is(tokenType))
            {
                Next_Token();
                return true;
            }

            Peek_Error(tokenType);
            return false;
        }

        /// <summary>
        /// 当下一个符号和预计的不相等时，则产生错误
        /// </summary>
        /// <param name="tokenType"></param>
        public void Peek_Error(TokenType tokenType)
        {
            m_errors.Add($"Expect next token to be {tokenType}, got {m_peek.Type} instead");
        }

        /// <summary>
        /// 获取当前符号的优先级
        /// </summary>
        /// <returns></returns>
        public Precedence Curr_Token_Precedence()
        {
            if (m_precedences.TryGetValue(m_curr.Type, out Precedence precedence))
                return precedence;
            return Precedence.LOWEST;
        }

        /// <summary>
        /// 获取下一个符号的优先级
        /// </summary>
        /// <returns></returns>
        public Precedence Peek_Token_Precedence()
        {
            if (m_precedences.TryGetValue(m_peek.Type, out Precedence precedence))
                return precedence;
            return Precedence.LOWEST;
        }

        /// <summary>
        /// 创建表达式
        /// </summary>
        /// <param name="precedence"></param>
        /// <returns></returns>
        public Expression Parse_Expression(Precedence precedence)
        {
            // 查找前缀表达式
            if (!m_prefix_parse_fns.TryGetValue(m_curr.Type, out var prefix))
            {
                no_prefix_parse_fn_error(m_curr.Type);
                return null;
            }

            // 查找中缀表达式
            Expression e = prefix();
            while ( !Peek_Token_Is(TokenType.SEMICOLON) && precedence < Peek_Token_Precedence())
            { 
                if (m_infix_parse_fns.TryGetValue(m_peek.Type,out var infix))
                {
                    Next_Token();
                    e = infix(e);
                }
                else
                {
                    return e;
                }
            }

            // 查找后缀表达式
            if (m_postfix_parse_fns.TryGetValue(m_peek.Type, out var postfix))
            {
                Next_Token();
                e = postfix(e);
            }

            return e;
        }

        /// <summary>
        /// 未找到前缀表达式的出错处理
        /// </summary>
        /// <param name="tokenType"></param>
        public void no_prefix_parse_fn_error(TokenType tokenType)
        {
            m_errors.Add($"no prefix parse function for {tokenType}");
        }
    }
}
